home *** CD-ROM | disk | FTP | other *** search
- /*
- * $Id: text.c,v 0.91 1994/02/20 00:53:02 zhao Pre-Release $
- *
- *. This file is part of BIT shareware package. After the two weeks of
- * free evaluation period, you are encouraged (required) to register
- * your copy for a small registration fee, which is $35 for personal use
- * and $50 for commercial, government and institutional use.
- *
- * Copyright(c) 1993, 1994 by T.C. Zhao.
- * All rights reserved.
- *
- * Permission to use, copy, and distribute this software in its entirety
- * for non-commercial purposes is hereby granted, provided that the
- * above shareware and copyright notices and this permission notice
- * appear in all copies and their documentation.
- *
- * This software may be modified for your own use, but modified versions
- * may not be distributed without prior consent of the author.
- *
- * This software is provided "as is" without expressed or implied
- * warranty of any kind.
- *
- *.
- *
- * Purpose:
- * Place arbitrary text on the image with automatic font switching to get
- * Greek letters, with same input method as in TeX.
- *
- * Needs a lot of more cleanup and abstraction. Also, this routine
- * does its own SaveUnders. Without support like X Pixmap, it is hard
- * to avoid framebuffer read.
- *
- * Moving text around is by default done via a simulated double buffereing
- * mechanism, which unfortunately could be slow on R3k or slower machines.
- *
- * BUGS: there is a leak in fontcache to avoid a bug in the fontmanager
- * (on IRIX 4.0.5 only ?), currently replying on font cache flushing to
- * limit the leak.
- *
- *
- */
- #if !defined(lint) && defined(F_ID)
- char *id_text = "$Id: text.c,v 0.91 1994/02/20 00:53:02 zhao Pre-Release $";
- #endif
-
- #include "bit.h"
- #include "fmclient.h"
- #include "extern.h"
- #include "dmalloc.h"
-
- #ifndef NO_FM_BUG
- #define FM_BUG
- #endif
-
- #include "symbol.h" /* fonts and special symbols */
- #include "tsdef.h" /* Token defination */
-
- /***************** Limits and defines ****************************/
-
- #define MINFSIZE 3.0 /* min fontsize allowd */
- #define MAXFSIZE 150.0 /* max fontsize allowd */
- #define MAXTEXT 31 /* max strings per image */
- #define MAXFONT 25 /* max no. of fonts */
- #define MAXSTR 512 /* max string length */
- #define SSHIFT 1 /* shadow shift */
- #define SSTEP 15 /* every sstep increase shadow by 1 */
- #define BW 1 /* for engrave & embossed */
-
- /* if requested font in particular size is not availble, the font
- manager substitutes another one, and thus the bounding box
- maybe wrong. Add EXTRA to the bounding box to guarantee cleanup
- */
- #define EXTRA 15 /* extra space for bounding box */
-
- #define TC 0 /* text color index */
- #define FC 1 /* frame color index */
- #define BC 2 /* bk color index */
-
- /*************** Local variables ******************************/
-
- static fmfonthandle fh[MAXFONT];/* All 1pt sized fonts */
- static char *fontname[MAXFONT]; /* and their names */
-
- static int mfindex; /* math(symbol) font index */
- static fmfonthandle mathfont[5];/* in different sizes */
- static fmfonthandle textfont[5];/* text font in different sizes */
- static int pmatch; /* if use printer width info */
-
- static int immediate = 1; /* default rendering method */
- static int placement = 1; /* alignment */
- static Line cline; /* current line */
-
- static IPTR limg; /* local copy of image pointer */
-
- /** Special effects */
- enum seffects
- {
- SE_normal, SE_shadow, SE_engraved, SE_embossed
- };
-
- static const char *seffect_name[] =
- {
- "Normal", "Shadow", "Engraved", "Embossed", 0
- };
-
- /* size command and corresponding font size delta */
- static const char *size_cmd[] =
- {
- "normal", "tiny", "small", "large", "huge"
- };
-
- static float fdelta[] =
- {
- 0, -4, -2, 2, 4
- };
-
- /***************************************************************
- * Text structure. Positions are relative to the the rasterimage
- **************************************************************/
- typedef struct
- {
- char *str; /* input string */
- Line *line; /* tokenized string */
- int findex; /* index into fh */
- fmfonthandle cfont; /* scaled, ready to use */
- int xi, yi; /* starting position >0 */
- int xt, yt; /* with proper justi */
- int w, h; /* repaint region */
- float size; /* text size int points */
- float rot; /* rot angle 0 <rot <360 */
- int col[3][4]; /* text, bk and frame color */
- int colm[4]; /* scaled with factor < 1 */
- int colp[4]; /* scaled with factor > 1 */
- short height; /* font height */
- short slant; /* slant in x dir */
- short descent; /* slant in y dir */
- short frame; /* if put a frame on */
- short bk; /* if frame and bk */
- short place; /* 0 l, 1 c, 2 r */
- short se; /* if shadow */
- }
- Text_t;
-
- static Text_t textbuf[MAXTEXT]; /* text saved */
- static Text_t cttext; /* working buf */
- static Text_t *tptr = &cttext; /* current text line */
- static char strbuf[MAXSTR + 2]; /* plus cursor + '\0' */
-
- static int xi, yi, xf, yf; /* rectangular bounds */
- static float vec[4][2]; /* rotated coordinats */
-
- static int lxi, lyi, lxf, lyf; /* For saveunder */
-
- /******************* Local functions ***************************/
-
- static Line *getlinemem(void);
- static void dupline(Line *, const Line *);
- static void freeline(Line *);
- static void sim_dbl_text_move(Text_t *);
- static void sgl_text_move(Text_t *);
- static void dbl_text_move(Text_t *);
- static void text_rasterize(Text_t *);
-
- static void
- save_last_position(void)
- {
- lxi = xi - EXTRA;
- lyi = yi - EXTRA;
- lxf = xf + EXTRA;
- lyf = yf + EXTRA;
- }
-
-
- /****************************************************************
- * Find next availale slot
- ****************************************************************/
-
- static Text_t *
- text_next(void)
- {
- register Text_t *tx = textbuf + MAXTEXT;
-
- while (--tx >= textbuf && tx->line)
- ;
-
- if (tx < textbuf)
- {
- M_err("NextText", "out of bounds");
- return 0;
- }
- return tx;
- }
-
- /*****************************************************************
- * save current text (tptr) into the structure
- *****************************************************************/
- static int
- text_save(void)
- {
- Text_t *tx = text_next();
-
- if (tx) /* ok */
- {
- memcpy(tx, tptr, sizeof(*tx));
-
- tx->str = strdup(strbuf);
- tx->line = getlinemem();
- dupline(tx->line, &cline);
-
- /* convert to image distance based */
- tx->xi -= limg->xi;
- tx->yi -= limg->yi;
- }
- return tx ? 0 : -1;
- }
-
- /****************************************************************
- * Remove a saved text
- *****************************************************************/
- static void
- text_free(Text_t * t)
- {
- if (t)
- {
- if (t->str)
- free(t->str);
- freeline(t->line);
- t->line = 0;
- }
- }
-
- /********************************************************************
- * Total number of text saved so far. Also re-arranges text
- * in a consecutive manner
- *******************************************************************/
- static Text_t *ttt[MAXTEXT];
- int
- number_of_text(void)
- {
- register int i = 0;
- register Text_t *tx = textbuf + MAXTEXT;
-
- while (--tx >= textbuf)
- if (tx->line)
- ttt[i++] = tx;
- return i;
- }
-
-
-
- /******************************************************************
- * get line width, taking into account of font change and size change
- *******************************************************************/
- static int
- get_line_width(Line * line)
- {
- int i;
- Token *t = line->token;
- int tw = 0;
-
- for (i = line->ntokens; --i >= 0; t++)
- {
- tw += fmgetstrwidth(t->math ?
- mathfont[t->isize] : textfont[t->isize], t->str);
- }
- return tw;
- }
-
- /*****************************************************************
- * Check if current font is the same as the last: Free all fonts
- * used if different and setnewfonts will re-generate needed fonts.
- ****************************************************************/
- static int
- font_diff(Text_t * t)
- {
- int diff;
- static int cfindex = -1; /* cache for last font */
- static float csize = -1.0; /* cache for last font */
- static lpmatch = -1;
-
- diff = ((cfindex != t->findex) || /* diff font */
- (lpmatch != pmatch) || /* diff font */
- (Abs(csize - t->size) > 0.1)); /* diff size */
-
- /*
- * free the old font if different. Can't do this because IRIX 4.05? has a
- * bug that will produce a segmentation fault
- */
-
- if (diff)
- { /* not first time */
-
- #ifndef FM_BUG /* The workaround */
- if (cfindex >= 0)
- {
- int i;
- for (i = 0; i < 5; i++)
- {
- fmfreefont(mathfont[i]);
- fmfreefont(textfont[i]);
- }
- }
- #endif
-
- cfindex = t->findex;
- lpmatch = pmatch;
- csize = t->size;
- }
- return diff;
- }
-
-
- /***********************************************************
- * Set text and math font for possible different sizes
- ***********************************************************/
- static void
- set_new_font(Text_t * t)
- {
- static fmfontinfo info;
- long owin = winget();
- static fmfonthandle lcfont; /* scaled, ready to use */
- float tmpfsize[6], tt;
- int i;
- float *tf = tmpfsize, *td = fdelta;
-
- /* set new font only if different from last */
- if (font_diff(t))
- {
-
- /* get all the sizes */
- *tf++ = (tt = t->size + *td++) > 1.0 ? tt : MINFSIZE;
- *tf++ = (tt = t->size + *td++) > 1.0 ? tt : MINFSIZE;
- *tf++ = (tt = t->size + *td++) > 1.0 ? tt : MINFSIZE;
- *tf++ = (tt = t->size + *td++) > 1.0 ? tt : MINFSIZE;
- *tf = (tt = t->size + *td) > 1.0 ? tt : MINFSIZE;
-
- /* validate all used fonts */
- for (i = 0; i < 5; i++)
- {
- mathfont[i] = fmscalefont(fh[mfindex], tmpfsize[i]);
- textfont[i] = fmscalefont(fh[t->findex], tmpfsize[i]);
- }
-
- /* current font */
- t->cfont = lcfont = textfont[0];
-
- M_info("SetNewFont", "FontCacheused: %ld", fmgetcacheused());
-
- /* install font */
- set_current_window(win_id);
- fmsetfont(t->cfont);
- fmgetfontinfo(t->cfont, &info);
- }
-
- /* record basic properties */
- t->cfont = lcfont;
- t->descent = info.yorig;
- t->slant = info.xorig;
- t->height = info.height - t->descent + 1;
- if (owin > 0)
- set_current_window(owin);
- }
-
- /********************************************************************
- * Find the box that encloses the text for repaint. VEC[4][i] are
- * the rotated coordinates of the box that bounds the text
- * while (xi, yi), (xf, yf) are the coordinates of the bounding box
- * that bounds everything.
- *
- * the unrotated bounding box:
- *
- * (-slant , h) (w + shift, h)
- * (-slant, descent) (w+shift, descent)
- *******************************************************************/
- static double pagematrix[3][2];
- #include <math.h>
- #define PI 3.1415926
- static void
- get_bounding_box(Text_t * t)
- {
- float sina, cosa;
- int i, sshift;
- float xo, yo;
- int ww, hh; /* the true width of text */
- float cxo, sxo, cyo, syo;
- float cww, sww, chh, shh;
- float xsf, ysf;
-
-
- /* basic size */
- t->w = get_line_width(t->line) + t->size / 5;
- t->h = t->height;
-
- /* calculate the shift caused by special effects */
-
- if (t->se == SE_shadow)
- {
- sshift = (SSHIFT + (t->size / SSTEP));
- xo = -(t->slant + 1);
- yo = -(t->descent + 1) - sshift - 1;
- ww = t->w + sshift;
- hh = t->h;
- }
- else if (t->se == SE_normal)
- {
- sshift = 0;
- xo = -(t->slant + 1);
- yo = -(t->descent + 1) - sshift - 2;
- ww = t->w;
- hh = t->h;
- }
- else
- {
- sshift = 1.0;
- xo = -(t->slant + 1) - 1;
- yo = -(t->descent + 1) - sshift - 2;
- ww = t->w + 2;
- hh = t->h + 2;
- }
-
-
- cosa = cos(t->rot * (PI / 180.0));
- sina = sin(t->rot * (PI / 180.0));
-
- cww = cosa * ww;
- sww = sina * ww;
-
- t->xt = t->xi;
- t->yt = t->yi;
-
- if (t->place == TCENTER)
- { /* center */
- xsf = 0.5 * cww;
- ysf = 0.5 * sww;
- }
- else if (t->place == TRIGHT)
- { /* left adjusted */
- xsf = cww;
- ysf = sww;
- }
- else
- {
- xsf = 0.0;
- ysf = 0.0;
- }
-
- t->xt -= xsf;
- t->yt -= ysf;
-
- /* get the rotated coordinates for the 4pt */
- /* (xo, yo) */
- vec[0][0] = (cxo = cosa * xo) - (syo = sina * yo) + t->xt;
- vec[0][1] = (sxo = sina * xo) + (cyo = cosa * yo) + t->yt;
-
- /* (w + shift, yo) */
- vec[1][0] = cww - syo + t->xt;
- vec[1][1] = sww + cyo + t->yt;
-
- /* (ww, h) */
- vec[2][0] = cww - (shh = sina * hh) + t->xt;
- vec[2][1] = sww + (chh = cosa * hh) + t->yt;
-
- /* (xo, h) */
- vec[3][0] = cxo - shh + t->xt;
- vec[3][1] = sxo + chh + t->yt;
-
-
- /* get lower-left and upper-right */
- xi = xf = vec[0][0];
- yi = yf = vec[0][1];
- for (i = 1; i < 4; i++)
- {
- if (xi > vec[i][0])
- xi = vec[i][0];
- if (xf < vec[i][0])
- xf = vec[i][0];
- if (yi > vec[i][1])
- yi = vec[i][1];
- if (yf < vec[i][1])
- yf = vec[i][1];
- }
-
- /* enlarge by 1 on all sides */
- xi--;
- yi--;
- xf++;
- yf++;
- }
-
- /********************************************************************
- * Generate a framebox
- *******************************************************************/
- static void
- make_frame(Text_t * t)
- {
- int i;
-
- if (t->bk)
- {
- Color4(t->col[BC]);
- bgnpolygon();
- for (i = 0; i < 4; i++)
- v2f(vec[i]);
- endpolygon();
- }
-
- if (t->frame)
- {
- Color4(t->col[FC]);
- bgnclosedline();
- for (i = 0; i < 4; i++)
- v2f(vec[i]);
- endclosedline();
- }
- }
-
- /**********************************************************************
- * We have the option to clean up the text by saving the screen or repaint
- * with the raster matrix depending on the definition of READSCR
- *
- * Do not know about Indigo, supposedly repeated read and write degrade the
- * image and in that case READSCR should be undefined.
- **********************************************************************/
-
- #define READSCR
-
- static void **spp;
-
- /****************************************************************
- * do a SaveUnder. If READSCR is not defined, we can use the image
- * in core as the backing store, save_under does nothing
- ***************************************************************/
- static void
- save_under(void)
- {
-
- #ifdef READSCR
-
- static int lsxi, lsyi, lsxf, lsyf;
- int moved;
-
- moved = (lxi - lsxi) || (lyi - lsyi) || (lxf - lsxf) || (lyf - lsyf);
-
- if (moved || !spp)
- {
-
- lsxi = lxi;
- lsyi = lyi;
- lsxf = lxf;
- lsyf = lyf;
- free_mat(spp);
- spp = get_mat(lyf - lyi + 1, lxf - lxi + 1, imgptr->esize);
- set_current_window(win_id);
- Rectread(lxi, lyi, lxf, lyf, spp[0]);
- }
-
- #endif
- }
-
- static void
- restore_piece(int txi, int tyi, int txf, int tyf)
- {
- if (txi != txf && spp)
- {
- set_current_window(win_id);
- reshapeviewport();
- #ifdef READSCR
-
- PI_rectwrite(txi, tyi, txf, tyf, spp[0]);
- #else
-
- img_rect_redraw(limg, txi, tyi, txf - txi + 1, tyf - tyi + 1);
- #endif
-
- }
- }
-
- /****************************************************************
- * The actuall routine that does the rendering at given location.
- * It does not rememeber where it did it.
- ****************************************************************/
- static void
- render_line(int x, int y, Line * line)
- {
- Token *t = line->token, *ts;
- static int lastmath = -1;
- static float lastsize = -1.0;
-
- set_current_window(win_id);
- reshapeviewport();
- cmov2i(x, y);
- for (ts = t + line->ntokens; t < ts; t++)
- {
- if (lastmath != t->math || Abs(lastsize - t->size) > 0.1)
- {
- fmsetfont(t->math ? mathfont[t->isize] : textfont[t->isize]);
- }
- fmprstr(t->str);
- }
- }
-
- /**********************************************************************
- * Routine takes care of frame and rotation and call render_line to
- * do the actual rendering
- *********************************************************************/
- static void
- text_draw_only(Text_t * t)
- {
- int sshift = (SSHIFT + (t->size / SSTEP)) * (t->se != SE_normal);
-
- set_current_window(win_id);
- reshapeviewport();
-
- if (t->bk || t->frame)
- make_frame(t);
-
- if (t->rot >= 0.1)
- {
- fmgetpagematrix(pagematrix);
- fmrotatepagematrix(t->rot);
- }
-
- if (t->se == SE_shadow)
- {
- scale_color(t->col[TC], 0.3, t->colm, 0, PCMAXV);
- Color4(t->colm);
- render_line(t->xt + sshift, t->yt - sshift, t->line);
- }
- else if (t->se == SE_engraved)
- {
- scale_color(t->col[TC], 0.3, t->colm, 80, PCMAXV);
- scale_color(t->col[TC], 2.0, t->colp, 200, PCMAXV);
- Color4(t->colm);
- render_line(t->xt - BW, t->yt + BW, t->line);
- Color4(t->colp);
- render_line(t->xt + BW, t->yt - BW, t->line);
- }
- else if (t->se == SE_embossed)
- {
- scale_color(t->col[TC], 0.3, t->colm, 80, PCMAXV);
- scale_color(t->col[TC], 2.0, t->colp, 200, PCMAXV);
- Color4(t->colp);
- render_line(t->xt - BW, t->yt + BW, t->line);
- Color4(t->colm);
- render_line(t->xt + BW, t->yt - BW, t->line);
- }
-
- /* the real text */
- Color4(t->col[TC]);
- render_line(t->xt, t->yt, t->line);
-
- /* Restore the pagematrix and free fontcache used */
- if (t->rot >= 0.1)
- {
- fmsetpagematrix(pagematrix);
- }
-
- }
-
- /********************************************************************
- * Draw and show
- ********************************************************************/
- static void
- text_draw(Text_t * t)
- {
-
- text_draw_only(t);
-
- #ifndef SGL_BUF
- if (double_buf)
- {
- swapbuffers();
- }
- #endif
- }
-
- /*****************************************************************
- * This routine takes care of rendering and moving, i.e., remember
- * where we did it.
- *****************************************************************/
- static void
- sgl_text_move(Text_t * t)
- {
-
- /* repaint the region where old text was */
- restore_piece(lxi, lyi, lxf, lyf);
-
- /* need to do this everytime to get the correct box */
- get_bounding_box(t);
-
- /* remember where we will do it */
- save_last_position();
- save_under();
- text_draw_only(t);
- }
-
- /*****************************************************************
- * move text in double buffer mode
- *****************************************************************/
- static int lastwme;
- static void
- dbl_text_move(Text_t * t)
- {
-
- /* need to do this everytime to get the correct box */
- get_bounding_box(t);
-
- /*
- * all text has the back buffer completely clean except when window
- * manager does the redraw, need to clean up the back buffer when last
- * redraw is wme
- */
-
- if (lastwme)
- {
- restore_piece(lxi, lyi, lxf, lyf);
- lastwme = 0;
- }
- /* remember where we will do it */
- text_draw(t);
- restore_piece(lxi, lyi, lxf, lyf);
- save_last_position();
- save_under();
- }
-
- static void
- text_move(Text_t * t)
- {
- long owin = winget();
- set_current_window(win_id);
- reshapeviewport();
-
- /*
- * can't use sim_dbl_buffer here because the need to completely redraw
- * the text string
- */
-
- (double_buf ? dbl_text_move : sgl_text_move) (t);
-
- if (owin > 0)
- set_current_window(owin);
- }
-
- /********************************************************************
- * This is the routine that sets new font (font family, size, rotation)
- *********************************************************************/
- static void
- render_text(Text_t * t)
- {
- if (!t || !t->line)
- return;
- set_new_font(t);
- text_move(t);
- }
-
- /*********************************************************************
- * initialize all fonts and get the font handle. Remove unavailable font
- * names
- ********************************************************************/
- static int
- init_fonts(void)
- {
- int i;
- static int n = -1;
-
- if (n > 0)
- return n;
-
- if (totalfont > MAXFONT)
- {
- totalfont = MAXFONT - 1;
- }
-
- fminit();
-
- /*
- * there are leaks currently, we need to make sure cache is large enuf,
- * about 2M
- */
-
- #ifdef FM_BUG
- fmsetcachelimit((1500 * 1000) / FMCACHE_QUANTUM);
- #endif
-
- fmcacheenable();
-
- n = i = 0;
- while (i < totalfont)
- {
- if ((fh[n] = fmfindfont(fonts[i])))
- {
- fontname[n] = fonts[i];
- if (strcmp(fontname[n], "Symbol") == 0)
- mfindex = n;
- n++;
- }
- i++;
- }
- fontname[n] = 0;
- return totalfont = n;
- }
-
- /*******************************************************************
- * Given a fontname fn, try to get the font index, findfont return.
- * If fn is bad, first available font index is returned.
- * MUST not return bogus index. On a related note, it is best
- * to have the first font index entry be a mon-spaced font.
- *******************************************************************/
- static int
- get_font_index(const char *fn)
- {
- int found, i;
-
- if (!init_fonts())
- {
- Bark("InitText", "Unable to load any fonts!!");
- return 0;
- }
- if (!fn || !*fn)
- return 0;
-
- i = -1;
- do
- {
- i++;
- found = strcmp(fontname[i], fn) == 0;
- }
- while (!found && i < totalfont - 1);
- return found ? i : 0;
- }
-
- /*******************************************************************
- * Support routines that parse the input string into tokens with many
- * attributes
- *****************************************************************{*/
- /* allocate memory for struct Line */
- static Line *
- getlinemem(void)
- {
- /* assuming char * has all zero bits for null */
- return calloc(1, sizeof(Line));
- }
-
- /* make a copy of struct line */
- static void
- dupline(Line * to, const Line * from)
- {
- const Token *t = from->token, *ts;
- Token *pt = to->token;
-
- if (!memcpy(to, from, sizeof(*from)))
- return;
-
- /* we are not done yet, members of line malloced */
- for (ts = t + from->ntokens; t < ts; t++, pt++)
- if (t->str)
- pt->str = strdup(t->str);
- return;
- }
-
- /* Free all memory allocated for a line */
- static void
- freeline(Line * line)
- {
- Token *t, *ts;
-
- if (!line)
- return;
-
- for (t = line->token, ts = t + line->ntokens; t < ts; t++)
- {
- if (t->str)
- free(t->str);
- t->str = 0;
- }
- }
-
- #ifdef SC_DEBUG
- static void
- print_tokens(Line * line)
- {
- int c;
-
- fprintf(stderr, "Total %d tokens\n", line->ntokens);
- for (c = 0; c < line->ntokens; c++)
- fprintf(stderr, "math=%d size=%.1f is=%d str=%s^\n",
- line->token[c].math, line->token[c].size,
- line->token[c].isize, line->token[c].str);
- }
-
- #endif
-
-
-
- /*************************************************************
- * check if a particular token is a sizing command, i.e.,
- * \small, \large etc
- **************************************************************/
- static int
- is_size(const char *p)
- {
- int i;
- for (i = sizeof(size_cmd) / sizeof(char *); --i >= 0;)
- if ((size_cmd[i][0] == *p) && strcmp(size_cmd[i], p) == 0)
- return i;
- return -1;
- }
-
- /******************************************************************
- * Add a new token to line and fix the special symbols on the fly
- * sz is the base size while isize is index into the modifier
- *******************************************************************/
- #include <ctype.h>
- static void
- new_token(Line * line, int m, float sz, int isize, char *str)
- {
- register char *s = str;
- char token[MAXSTR], ltok[MAXSTR];
- char *ct, *lct;
- Token *t = &line->token[line->ntokens];
-
- if (!*str)
- return;
-
- t->math = m;
- if (isize < 0)
- isize = 0;
- t->isize = isize;
- t->size = sz + fdelta[isize];
- /* there is no point print a string you can't see */
- if (t->size < MINFSIZE)
- t->size = MINFSIZE;
-
- if (t->str)
- free(t->str);
-
- ct = token;
- while (*s)
- {
- switch (*s)
- {
- case '\\':
- lct = ltok;
- while (*++s && isalnum(*s))
- *lct++ = *s;
- *lct = '\0';
- *ct = '\0';
- /* mathcode returns a string of length 1 or more */
- strcat(token, m ? mathcode(ltok) : spcode(ltok));
- ct = token + strlen(token);
- --s;
- break;
- default:
- *ct++ = *s;
- break;
- }
- if (*s)
- s++;
- }
- *ct = '\0';
- t->str = strdup(token);
- line->ntokens++;
- if (line->ntokens >= MAXTOK)
- {
- M_warn("TextAddToken", "No. of tokens out of bounds");
- line->ntokens = MAXTOK - 1;
- }
- }
-
- /**********************************************************************
- * Break a line into tokens. A token is defined as a string uninterrupted
- * by font switching ($) or size change \small etc
- * Base size is sz
- **********************************************************************/
- static void
- tokenize(char *str, Line * line, float sz)
- {
- register char *p = str;
- register char *ct, *lct;
- register int math = 0;
- float size = sz;
- int isize = 0;
- register int c;
- char ctoken[MAXSTR], ltoken[MAXSTR];
-
- line->ntokens = 0;
- ct = ctoken;
- ltoken[0] = '\0';
-
- while (p && *p)
- {
- switch (*p)
- {
- case '$':
- *ct = '\0';
- new_token(line, math, size, isize, ctoken);
- ct = ctoken;
- math = !math;
- break;
- case '\\':
- c = *++p; /* skip \\ */
- if (c == '\\' || c == '$')
- { /* escape */
- *ct++ = c;
- }
- else if (c)
- { /* a true token. */
- lct = ltoken;
- *lct++ = '\\';
- *lct++ = c;
- while (*++p && isalpha(*p))
- *lct++ = *p;
- *lct = '\0';
- /* check if sizing command */
- if ((c = is_size(ltoken + 1)) >= 0)
- {
- *ct = '\0';
- new_token(line, math, size, isize, ctoken);
- isize = c;
- ct = ctoken;
- }
- else
- { /* not a size command, keep it */
- *lct = '\0';
- *ct = '\0';
- strcat(ctoken, ltoken);
- ct = ctoken + strlen(ctoken);
- }
- --p; /* backup */
- }
- break;
- default:
- *ct++ = *p;
- }
- if (*p)
- p++;
- }
- *ct = '\0';
-
- if (math)
- M_info("ScanLine", "Unfinished math");
-
- if (math)
- {
- /* show only complete symbols */
- p = (ct = strrchr(ctoken, ' ')) ? ct : strrchr(ctoken, '\\');
- if (p)
- *p = '\0';
- }
- new_token(line, math, size, isize, ctoken);
- #ifdef SC_DEBUG
- print_tokens(line);
- #endif
- }
-
- /***********************************************************************
- * END OF SUPPORT ROUTINES
- *******************************************************************}*/
-
- /*
- * routine to add text. To be called non-interactively.
- */
- void
- img_add_text(IPTR im, const char *s, const char *f,
- float tsize, float trot, rgba_t tc, int x, int y, int bk,
- rgba_t bc, int fr, rgba_t fc, int sh, int pl)
- {
- Text_t *t;
- int i, r, g, b;
-
- if (!im || !s)
- return;
-
- t = text_next();
- memset(t, 0, sizeof(*t));
- t->line = getlinemem();
- t->str = strdup(s);
- t->place = 0;
- t->xi = x;
- t->yi = y;
-
- Unpack(tc, r, g, b);
- t->col[TC][0] = r;
- t->col[TC][1] = g;
- t->col[TC][2] = b;
-
- Unpack(fc, r, g, b);
- t->col[FC][0] = r;
- t->col[FC][1] = g;
- t->col[FC][2] = b;
-
- Unpack(bc, r, g, b);
- t->col[BC][0] = r;
- t->col[BC][1] = g;
- t->col[BC][2] = b;
-
- if (IS_CI(im))
- {
- for (i = 0; i < 3; i++)
- t->col[i][3] = cmap_closematch(im->cmap, t->col[i][0],
- t->col[i][1], t->col[i][2]);
- }
-
- t->bk = bk;
- t->frame = fr;
- t->size = tsize;
- t->rot = trot;
- t->findex = get_font_index(f);
- t->se = sh;
- t->place = pl;
- tokenize(t->str, t->line, t->size);
- }
-
-
- const char *
- get_text_fontname(int nt)
- {
- return fontname[ttt[nt]->findex];
- }
-
- float
- get_text_fontsize(int nt)
- {
- return ttt[nt]->size;
- }
-
- const char *
- get_text_string(int nt)
- {
- return ttt[nt]->str;
- }
-
- Line *
- get_text_line(int nt)
- {
- return ttt[nt]->line;
- }
-
- int
- get_text_placement(int nt)
- {
- return ttt[nt]->place;
- }
-
- void
- get_text_location(int nt, int *x, int *y)
- {
- *x = ttt[nt]->xi;
- *y = ttt[nt]->yi;
- }
-
- float
- get_text_rotation(int nt)
- {
- return ttt[nt]->rot;
- }
-
- int
- get_fm_cache(void)
- {
- return (fmcachelimit() * FMCACHE_QUANTUM / 1000);
- }
-
- int
- get_fm_cacheused(void)
- {
- return (fmgetcacheused() / 1000);
- }
-
- /*************************************************************************
- * get max sizes of texts that sticks out of the image, only approximately
- * by using mono space and ignoring rotation
- ************************************************************************/
- void
- get_text_bounds(IPTR im, int *top, int *left, int *bottom, int *right)
- {
- Text_t *tx = textbuf + MAXTEXT;
- int l = 0, b = 0, t = im->h, r = im->w;
-
- while (--tx >= textbuf)
- {
- ; /* to be written */
- }
- *top = t - im->h;
- *left = -l;
- *bottom = -b;
- *right = r - im->w;
- }
-
- /*
- * can't use limg because this routine can be called anywhere
- */
- void
- get_text_color(int nt, int *r, int *g, int *b)
- {
- int i;
-
- if (IS_CI(imgptr))
- {
- i = ttt[nt]->col[TC][3];
- *r = imgptr->cmap->ct[0][i];
- *g = imgptr->cmap->ct[0][i];
- *b = imgptr->cmap->ct[0][i];
- }
- else
- {
- *r = ttt[nt]->col[TC][0];
- *g = ttt[nt]->col[TC][1];
- *b = ttt[nt]->col[TC][2];
- }
- }
-
- /*
- * Delete all text saved and free all spaces
- */
- void
- del_text(void)
- {
- Text_t *tx = textbuf + MAXTEXT;
-
- while (--tx >= textbuf)
- {
- if (!tx->line)
- continue;
- text_free(tx);
- }
- }
-
- /******************************************************************
- * Display current saved text.
- *
- * This routine could be called by various routines, including
- * display, or window resizing events handlers. In any case,
- * this routine should not alter buffer settings (back, front etc).
- ******************************************************************/
-
- static int active; /* true if entered thru do_text */
- void
- display_text(IPTR im)
- {
- Text_t *t = textbuf + MAXTEXT;
-
- init_text();
-
- /* If bad image, silently return */
- if (im->ok <= 0)
- return;
-
- while (--t >= textbuf)
- {
- if (t->line)
- {
- t->xi += im->xi;
- t->yi += im->yi;
- set_new_font(t);
- get_bounding_box(t);
- text_draw_only(t);
- t->xi -= im->xi;
- t->yi -= im->yi;
- }
- }
-
- /*
- * active means we are currently in text mode, and therefore need to
- * re-draw the current text as well
- */
-
- if (active)
- {
- set_new_font(tptr);
- sgl_text_move(tptr);
- lastwme = 1;
- }
- }
-
-
- /***********************************************************************
- * Save to and restore from disk. Could've dumped the whole structure out,
- * but ASCII will be portable.
- */
- void
- dump_text(FILE * fp)
- {
- Text_t *t = textbuf + MAXTEXT;
-
- fprintf(fp, "#TX %d\n", number_of_text());
- /* can't stick # in front */
- fputs(" Font Size Rot Text_t Tc Bc Fc X Y bk fr sh just\n", fp);
-
- while (--t >= textbuf)
- {
- if (!t->line)
- continue;
- fprintf(fp, "#%s %.2f %.1f\n", fonts[t->findex], t->size, t->rot);
- fprintf(fp, "%s\n", t->str);
- fprintf(fp, "%g %g %g %g %g %g %g %g %g\n",
- C2NC(t->col[0][0]), C2NC(t->col[0][1]), C2NC(t->col[0][2]),
- C2NC(t->col[1][0]), C2NC(t->col[1][1]), C2NC(t->col[1][2]),
- C2NC(t->col[2][0]), C2NC(t->col[2][1]), C2NC(t->col[2][2]));
- fprintf(fp, "%d %d %d %d %d %d \n", t->xi, t->yi, t->bk, t->frame,
- t->se, t->place);
- }
- }
-
- /**********************************************************
- * load text from disk.
- ***********************************************************/
- void
- load_text(IPTR im)
- {
- int n, i, j;
- char fname[60], *p;
- float fsize, trot, f;
- int x, y, r, g, b;
- rgba_t cc[3];
- int bk, fr, sh, pl;
- FILE *fp = im->fp;
-
- while ((n = getc(fp)) != EOF && n != '#')
- ;
- if (n != '#' || (n = getc(fp) != 'T') || (n = getc(fp)) != 'X')
- return;
-
- n = readpint(fp);
-
- if (n <= 0)
- return;
- if (n >= MAXTEXT)
- { /* can't happen */
- Bark("LoadText", "Total %d strings %s", n, outbound);
- return;
- }
- M_info("LoadText", "%d strings found", n);
-
- for (i = 0; i < n; i++)
- {
- while (fgets(strbuf, MAXSTR, fp) && strbuf[0] != '#')
- ;
- if (strbuf[0] != '#')
- {
- M_warn("LoadText", "More are expected");
- return;
- }
- sscanf(strbuf + 1, "%s %f %f", fname, &fsize, &trot);
- fgets(strbuf, MAXSTR, fp);
- /* remove newline */
- if ((p = strchr(strbuf, '\n')))
- *p = '\0';
- for (j = 0; j < 3; j++)
- {
- f = readfloat(fp);
- r = NC2C(f);
- f = readfloat(fp);
- g = NC2C(f);
- f = readfloat(fp);
- b = NC2C(f);
- cc[j] = Pack(r, g, b);
- }
- x = readint(fp);
- y = readint(fp);
- bk = readint(fp);
- fr = readint(fp);
- sh = readint(fp);
- pl = readint(fp);
- img_add_text(im, strbuf, fname, fsize, trot, cc[TC],
- x, y, bk, cc[BC], fr, cc[FC], sh, pl);
- }
- }
-
- /********************************************************************
- * convert text to gray. need only change the RGB representation.
- * This routine is called after a type conversion
- ********************************************************************/
- void
- text_to_gray(void)
- {
- register int q;
- Text_t *t = textbuf + MAXTEXT;
- int *cc;
-
- while (--t >= textbuf)
- {
- if (!t->line)
- continue;
-
- cc = t->col[TC];
- q = rgb2gray(cc[0], cc[1], cc[2]);
- cc[0] = cc[1] = cc[2] = q;
-
- cc = t->col[BC];
- q = rgb2gray(cc[0], cc[1], cc[2]);
- cc[0] = cc[1] = cc[2] = q;
-
- cc = t->col[FC];
- q = rgb2gray(cc[0], cc[1], cc[2]);
- cc[0] = cc[1] = cc[2] = q;
-
- }
- }
-
- /*************************************************************
- * Convert text color from RGB based to index based. Called
- * after image type conversion, i.e., quantization. Not
- * possible to honour exact colors, do the best we can
- * from the colormap.
- *************************************************************/
- void
- text_to_cmap(void)
- {
- Text_t *t = textbuf + MAXTEXT;
- int *cc;
-
- if (!IS_CI(imgptr))
- return;
-
- while (--t >= textbuf)
- {
- if (!t->line)
- continue;
-
- cc = t->col[TC];
- cc[3] = cmap_closematch(imgptr->cmap, cc[0], cc[1], cc[2]);
-
- cc = t->col[BC];
- cc[3] = cmap_closematch(imgptr->cmap, cc[0], cc[1], cc[2]);
-
- cc = t->col[FC];
- cc[3] = cmap_closematch(imgptr->cmap, cc[0], cc[1], cc[2]);
-
- }
- }
-
- /************************************************************
- *
- * GUI part of the Text routines.
- *
- * Fills the Text_t structure and show its effect
- *
- ************************************************************/
-
- #define MINTXSIZE 1.0 /* minimum text size */
- #define TXSTEP1 1.0 /* minimum delta */
- #define TXSTEP2 5.0 /* maximum delta */
-
- /*ARGSUSED */
- static void
- immediate_cb(FL_OBJECT * ob, long q)
- {
- immediate = fl_get_choice(ob) - 1;
- }
-
- /* default size for shortcuts */
- static const float fsize[] =
- {
- 5.0, 8.0, 10.0, 12.0, 14.0, 20.0
- };
-
- /* default shortcuts for orientation */
- static const float rangle[] =
- {
- 0, 90, 180, 270
- };
-
- static int indexs = 2; /* default size index */
- static int indexr; /* default orientation */
- static FL_FORM *textform;
- static FL_OBJECT *fchoice;
- static FL_OBJECT *input, *rcounter, *scounter, *effects;
- static FL_OBJECT *col[3], *frame, *bk, *size[6], *ra[4];
-
- /*********************************************************
- * Initialize fonts, form entries, etc
- *********************************************************/
- static void create_form_text(void);
- int
- init_text(void)
- {
- int i;
- char **p;
- char tmp[20];
- static int init;
- static const char *dirtext[] =
- {
- "Horiz", "90", "180", "-90"
- };
-
- if (init > 0)
- return init;
-
- show_busy("LoadingFonts ...");
-
- /* find all fonts */
- if (!init_fonts())
- {
- Bark("InitText", "Unable to load any fonts!!");
- return -1;
- }
-
- init = totalfont;
- create_form_text();
-
- /* fill the font choices */
- fl_clear_choice(fchoice);
- for (p = fontname; p && *p; p++)
- fl_addto_choice(fchoice, *p);
- fl_set_choice(fchoice, 1);
-
-
- /* cleanr all size buttons and set default */
- for (i = 0; i < 6; i++)
- {
- fl_set_button(size[i], 0);
- sprintf(tmp, "%.0fpt", fsize[i]);
- fl_set_object_label(size[i], tmp);
- }
- fl_set_button(size[indexs], 1);
-
- /* set size counter default for arbitrary size */
- fl_set_counter_precision(scounter, 1);
- fl_set_counter_bounds(scounter, MINTXSIZE, MAXFSIZE);
- fl_set_counter_step(scounter, TXSTEP1, TXSTEP2);
- fl_set_counter_value(scounter, fsize[indexs]);
-
- /* cleanr all rotation buttons and set default */
- for (i = 0; i < 4; i++)
- {
- fl_set_button(ra[i], 0);
- fl_set_object_label(ra[i], dirtext[i]);
- }
- fl_set_button(ra[indexr], 1);
-
- /* set rotation counter default */
- fl_set_counter_precision(rcounter, 0);
- fl_set_counter_bounds(rcounter, 0.0, 360.0);
- fl_set_counter_step(rcounter, 1, 10);
- fl_set_counter_value(rcounter, rangle[indexr]);
-
- /* misc */
- fl_set_button(frame, 0);
- fl_set_button(bk, 0);
- fl_set_input_return(input, 1);
- end_busy();
- return init;
- }
-
-
- /*********************************************************************
- * default Text color, Frame color and background color
- ********************************************************************/
- static int lcol[][4] =
- {
- {0, 0, 0, 0}, /* text color */
- {PCMAXV, 0, 0, 1}, /* frame color */
- {PCMAXV, PCMAXV, PCMAXV, 0} /* background color */
- };
-
-
- /*****************************************************************
- * Every time do_text is called, this routine will be called to set
- * current size, color etc.
- *****************************************************************/
- static void
- set_text_default(Text_t * t)
- {
- int i;
-
- strcpy(strbuf, limg->ifile);
- fl_set_input(input, strbuf);
-
- t->size = fl_get_counter_value(scounter);
- t->findex = fl_get_choice(fchoice) - 1;
- t->frame = fl_get_button(frame);
- t->se = fl_get_choice(effects) - 1;
- t->bk = fl_get_button(bk);
- t->rot = fl_get_counter_value(rcounter);
- t->place = placement;
- t->xi = win_w / 2 - 10;
- t->yi = win_h / 2 - 10;
-
- for (i = 0; i < 4; i++)
- {
- t->col[TC][i] = lcol[0][i];
- t->col[FC][i] = lcol[1][i];
- t->col[BC][i] = lcol[2][i];
- }
- tokenize(strbuf, t->line, t->size);
- }
-
-
- /***********************************************************
- * Handle mouse events: Depending on various options,
- * either double buffer, simulated double buffer and single
- * buffer mode will be used. Note that in defered mode, current
- * code is not capable of simulating double buffering without
- * messing up the screen
- **********************************************************/
- static void
- handle_mouse(Text_t * t)
- {
- void (*moveit) (Text_t *);
- int mx, my;
-
- if (!double_buf && simu_dbl_buffer && immediate)
- text_rasterize(t);
-
- /* hardware double buffering overrites other settings */
- moveit = double_buf ? dbl_text_move :
- ((simu_dbl_buffer && immediate) ? sim_dbl_text_move : sgl_text_move);
-
- M_info("TextMouse", moveit == dbl_text_move ? "DoubleBuffer" :
- (moveit == sim_dbl_text_move ?
- "SimuDblBuffer" : "SglBuffer"));
-
- do
- {
- WHERE_R2W(mx, my, win_xo, win_yo);
- if (mx != t->xi || my != t->yi)
- {
- show_mouse_position(mx, my);
- t->xi = mx;
- t->yi = my;
- moveit(t);
- }
- }
- while (mouse_down);
-
- if (!double_buf && simu_dbl_buffer && immediate)
- {
- free_mat(spp);
- spp = no_fail_get_subimage(imgptr, lxi, lyi,
- lxf - lxi + 1, lyf - lyi + 1);
- }
- }
-
- /*****************************************************************
- * Simulate double buffering
- *****************************************************************/
- static int diffcolor;
- #ifndef NO_NP_DBL /* { */
- static void **rastext;
- static int rash, rasw;
-
- static int
- attribute_diff(Text_t * t)
- {
- static float rotated = -1;
- static int lframe = -1, lbk = -1;
- static char lstrbuf[MAXSTR + 2]; /* plus cursor + '\0' */
- static int leffects = -1;
- int diff;
-
- diff = (t->bk - lbk) || /* diff background */
- (t->frame - lframe) || /* diff frame */
- (Abs(t->rot - rotated) > 0.5) || diffcolor ||
- (t->se - leffects) || strcmp(lstrbuf, strbuf);
-
- if (diff)
- {
- lbk = t->bk;
- lframe = t->frame;
- rotated = t->rot;
- leffects = t->se;
- diffcolor = 0;
- strcpy(lstrbuf, strbuf);
- }
- return diff;
- }
-
- static int
- bad_magic_pix(rgba_t m)
- {
- if (IS_CPACK(imgptr))
- {
- rgba_t txc, bkc, fmc;
-
- txc = Pack(lcol[TC][0], lcol[TC][1], lcol[TC][2]);
- bkc = Pack(lcol[BC][0], lcol[BC][1], lcol[BC][2]);
- fmc = Pack(lcol[FC][0], lcol[FC][1], lcol[FC][2]);
- return (m == txc || m == bkc || m == fmc);
- }
- else
- {
- return (m == lcol[TC][3] ||
- m == lcol[BC][3] ||
- m == lcol[FC][3]);
- }
- }
-
- /**********************************************************************
- * Rasterize a text string: reads the screen buffer. Someday,
- * it should be replaced with feekback from the GE.
- * only should be called within handle_mouse
- **********************************************************************/
- static void
- text_rasterize(Text_t * t)
- {
- static int incomplete;
- static int cfindex = -1;
- static int csize = -1.0;
- static int lpmatch = -1;
- rgba_t magicpix = 0;
-
- /* can't simple use font_diff because render_text sets it */
- int diff = ((cfindex != t->findex) || /* diff font */
- (lpmatch != pmatch) || /* diff font */
- (Abs(csize - t->size) > 0.1)); /* diff size */
-
- /* if no backing store, can't rasterize */
- if (lxi == lxf || !spp)
- {
- M_err("TextRasterize", "Failed to rasterize");
- return;
- }
-
- if (!attribute_diff(t) && !diff && !incomplete && rastext)
- return;
-
- /* if last is incomplete, need to re-generate the text */
- if ((incomplete = (lxi <= 0 || lyi <= 0 || lxf >= win_w || lyf >= win_h)))
- {
- int mx, my;
-
- WHERE_R2W(mx, my, win_xo, win_yo);
- t->xi = mx;
- t->yi = my;
- sgl_text_move(t);
- }
-
- rasw = lxf - lxi + 1;
- rash = lyf - lyi + 1;
- M_info("RasterizeText", "w=%d h=%d", rasw, rash);
-
- free_mat(rastext);
- rastext = get_mat(rash, rasw, imgptr->esize);
-
-
- PI_rectread(lxi, lyi, lxf, lyf, rastext[0]);
- PI_rectwrite(lxi, lyi, lxf, lyf, spp[0]);
-
- /*
- * check to make sure that the magic pixel is NOT one of the text color,
- * background color or framecolor
- */
- while (bad_magic_pix(magicpix))
- magicpix++;
-
- set_magic_pix(magicpix);
-
- if (IS_CPACK(imgptr))
- {
- rgba_t *p, *q, *qs;
-
- /* rasterize */
- p = spp[0];
- q = rastext[0];
- qs = q + rash * rasw;
-
- while (q < qs)
- {
- *q = (*q == *p) ? magicpix : *q;
- q++;
- p++;
- }
- }
- else
- {
- ci_t *p, *q, *qs;
- /* rasterize */
- p = spp[0];
- q = rastext[0];
- qs = q + rash * rasw;
-
- while (q < qs)
- {
- *q = (*q == *p) ? magicpix : *q;
- q++;
- p++;
- }
- }
-
- cfindex = t->findex;
- csize = t->size;
- lpmatch = pmatch;
-
- if (incomplete)
- {
- text_draw(t);
- }
- /* update for possible sgl_text_move call */
- incomplete = (lxi <= 0 || lyi <= 0 || lxf >= win_w || lyf >= win_h);
-
- }
-
- static void
- sim_dbl_text_move(Text_t * t)
- {
-
- if (!rastext)
- {
- text_move(t);
- return;
- }
- get_bounding_box(t);
- sim_dbl_swap(imgptr, rasw, rash, rastext,
- xi - EXTRA, yi - EXTRA, lxi - EXTRA, lyi - EXTRA, O_MASK);
- save_last_position();
- }
-
- #endif /* } */
- /*********************************************************************
- * In addition of saving current text
- * NL indicates move the current text "down" 1 line
- *********************************************************************/
- static void
- save_text(int nl)
- {
- int k = strlen(strbuf);
-
- /* if empty string, do nothing */
- if (k == 0)
- return;
-
-
- if (immediate)
- { /* need to render it into raster */
- set_current_window(win_id);
- if (double_buf)
- text_draw(tptr);
- fb_to_ras(limg, make_rect(lxi, lyi, lxf - lxi + 1, lyf - lyi - 1));
- if (!spp)
- spp = get_mat(lyf - lyi + 1, lxf - lxi + 1, limg->esize);
- Rectread(lxi, lyi, lxf, lyf, spp[0]);
- }
- else
- {
- text_save(); /* save it to structure */
-
- /*
- * do it one more time so that next save under will not screw up
- * the move
- */
- lxi = lxf = -1;
- text_draw(tptr);
- }
-
- /* requested nextline, figure out where it should be */
- if (nl)
- {
- float dh = 1.02 * tptr->height;
- tptr->xi += dh * sin(tptr->rot * PI / 180.0);
- tptr->yi -= dh * cos(tptr->rot * PI / 180.0);
- lxi = lxf = -1;
- text_move(tptr);
- }
- }
-
- /******************************************************************
- * wm_handler is called by repaint to handle unknown repaint
- * events from the window manager, e.g., resize, position change etc.
- ******************************************************************/
- static int
- text_wm_handler(IPTR im, int wme)
- {
- static int imxi, imyi;
-
- if (wme > 0)
- {
- tptr->xi += (im->xi - imxi);
- tptr->yi += (im->yi - imyi);
- lxi += (im->xi - imxi);
- lyi += (im->yi - imyi);
- lxf += (im->xi - imxi);
- lyf += (im->yi - imyi);
- }
-
- imxi = im->xi;
- imyi = im->yi;
-
- /*
- * display text at the new location will be taken care of by
- * display_text, which is called by the dispatcher in do_repaint
- */
- return 0;
- }
-
- /***********************************************************
- * Process keyboard input
- ***********************************************************/
- static int
- text_keybd(Text_t * t, int val)
- {
- int ret = 0;
- static int step = 1;
-
- switch (val)
- {
- case 'h':
- case 'H':
- t->xi -= step;
- break;
- case 'j':
- case 'J':
- t->yi -= step;
- break;
- case 'k':
- case 'K':
- t->yi += step;
- break;
- case 'l':
- case 'L':
- t->xi += step;
- break;
- case 27:
- ret = -1;
- break;
- default:
- if (val > '0' && val <= '9')
- step = val - '0';
- ret = 1;
- break;
- }
-
- if (ret >= 0)
- {
- text_move(tptr);
- ret = 0;
- }
- return ret;
- }
-
- /*******************************************************
- * This is the global entry point
- ********************************************************/
- int
- do_text(IPTR im)
- {
- short val;
- int done;
-
- if (init_text() <= 0)
- return -1;
-
- install_wm_handler(text_wm_handler);
- text_wm_handler(im, 0); /* initialize position */
-
- limg = im;
- lastwme = 0;
-
- bit_show_form(textform, FL_PLACE_MOUSE, 0, "Text");
- active = 1;
-
- /*
- * setting lxi < 0 effectively prevents the text rendering routine from
- * repaint last postion
- */
-
- lxi = lxf = -1;
- tptr->line = &cline;
- set_text_default(tptr);
-
- render_text(tptr);
-
- done = 0;
- do
- {
- switch (bit_qread(&val))
- {
- case LEFTMOUSE:
- if (val)
- handle_mouse(tptr);
- break;
- case KEYBD:
- done = text_keybd(tptr, val);
- break;
- case UPARROWKEY:
- if (val)
- text_keybd(tptr, 'k');
- break;
- case DOWNARROWKEY:
- if (val)
- text_keybd(tptr, 'j');
- break;
- case LEFTARROWKEY:
- if (val)
- text_keybd(tptr, 'h');
- break;
- case RIGHTARROWKEY:
- if (val)
- text_keybd(tptr, 'l');
- break;
- }
- }
- while (!done);
-
- /*
- * note resetting of active must appear before hide_form since hide_form
- * generates an input event(bug?) and by that time line might've been
- * freed
- */
-
- hide_getcolor();
- remove_wm_handler(text_wm_handler);
- active = 0;
-
- #ifndef SGL_BUF
- if (double_buf)
- {
- if (lastwme)
- restore_piece(lxi, lyi, lxf, lyf);
- swapbuffers();
- lastwme = 0;
- }
- #endif
-
- restore_piece(lxi, lyi, lxf, lyf);
-
- bit_hide_form(textform);
- freeline(&cline);
-
- #ifndef NO_NP_DBL
- free_mat(rastext);
- rastext = 0;
- set_magic_pix(0);
-
- #endif
-
- #ifdef READSCR
- free_mat(spp);
- spp = 0;
- #endif
-
- return 0;
- }
-
- /************************************************************************
- * Call back routine when the state of size button/counter is changed.
- * Shadow strength should be a function of of the font size
- ***********************************************************************/
- /* ARGSUSED */
- static void
- preview_cb(FL_OBJECT * ob, long p)
- {
- pmatch = fl_get_choice(ob) > 1;
- fmprintermatch(pmatch);
- render_text(tptr);
- }
-
- /* ARGSUSED */
- static void
- fontsize_cb(FL_OBJECT * p, long q)
- {
- int i;
-
- if (p == scounter)
- {
- tptr->size = fl_get_counter_value(p);
- for (i = 0; i < sizeof(fsize) / sizeof(float); i++)
- {
- /*
- * if the size matches one of the predefined size, lit up the
- * button
- */
- fl_set_button(size[i], (fabs(tptr->size - fsize[i]) < 0.05));
- }
- }
- else
- {
- tptr->size = fsize[q];
- fl_set_counter_value(scounter, tptr->size);
- }
- render_text(tptr);
- }
-
- /* ARGSUSED */
- static void
- justification_cb(FL_OBJECT * p, long q)
- {
- tptr->place = placement = fl_get_choice(p) - 1;
- }
-
- /* ARGSUSED */
- static void
- select_orientation(FL_OBJECT * p, long q)
- {
- int i;
- static float lastc;
-
- if (p == rcounter)
- {
- tptr->rot = fl_get_counter_value(p);
- if (fabs(tptr->rot - 360.0) < 0.5)
- {
- tptr->rot = 0;
- fl_set_counter_value(p, 0.0);
- }
- for (i = 0; i < sizeof(rangle) / sizeof(float); i++)
- {
- /*
- * if current angle matches predefined angles, lit up the
- * button else turn it off
- */
- fl_set_button(ra[i], (fabs(tptr->rot - rangle[i]) < 0.5));
- }
- }
- else
- {
- tptr->rot = rangle[q];
- fl_set_counter_value(rcounter, tptr->rot);
- }
-
- /* redraw text only if different from last */
- if (fabs(lastc - tptr->rot) > 0.5)
- render_text(tptr);
- lastc = tptr->rot;
- }
-
- /***************************************************************
- * New font request
- **************************************************************/
- /* ARGSUSED */
- static void
- select_font(FL_OBJECT * p, long q)
- {
- int f = fl_get_choice(fchoice) - 1;
-
- if (f >= 0)
- tptr->findex = f;
- render_text(tptr);
- }
-
- /********************************************************************
- * call back routine when new text is entered
- ******************************************************************/
- /* ARGSUSED */
- static void
- get_newtext(FL_OBJECT * p, long q)
- {
- /*
- * It would appear that hiding a form generates an input event and this
- * routine will be called. Must turn active off before hiding form
- */
- if (!active)
- return;
- Strncpy(strbuf, fl_get_input(input), MAXSTR);
- tokenize(strbuf, tptr->line, tptr->size);
- text_move(tptr);
- }
-
- /****************************************************************
- * Color call back routine. If the image is colormap, counted on
- * get_color to do the right thing with the colormap index
- ***************************************************************/
- static int currentq; /* color current working on */
-
-
- static void
- handle_color_change(int cc[])
- {
- int q = currentq;
- static int lastq;
-
- tptr->col[q][0] = cc[0];
- tptr->col[q][1] = cc[1];
- tptr->col[q][2] = cc[2];
- tptr->col[q][3] = cc[3];
-
- if (lastq != q)
- get_bounding_box(tptr);
-
- /* we have to always keep the backbuffer clean */
- #if 1
- render_text(tptr);
- #else
- (double_buf ? text_move : text_draw) (tptr);
- #endif
- lastq = q;
- diffcolor = 1;
- }
-
- /*****************************************************************
- * call back routine for which color currently we are working on
- ****************************************************************/
- /* ARGSUSED */
- static void
- select_color_cb(FL_OBJECT * p, long q)
- {
- currentq = q;
- set_getcolor_cb(handle_color_change);
- get_color(imgptr, lcol[q], 0);
- }
-
- /**************************************************************
- * misc. changes
- *************************************************************/
- /* ARGSUSED */
- static void
- se_call_back(FL_OBJECT * p, long q)
- {
- tptr->se = fl_get_choice(effects) - 1;
- render_text(tptr);
- }
-
- /* ARGSUSED */
- static void
- frame_bk_cb(FL_OBJECT * p, long q)
- {
- static int lframe, lbk, leffects;
-
- tptr->frame = fl_get_button(frame);
- tptr->bk = fl_get_button(bk);
- tptr->se = fl_get_choice(effects) - 1;
-
- if (!tptr->bk)
- {
- fl_set_object_lcol(col[2], FL_INACTIVE);
- fl_deactivate_object(col[2]);
- }
- else
- {
- fl_set_object_lcol(col[2], FL_BLACK);
- fl_activate_object(col[2]);
- }
-
- if (!tptr->frame)
- {
- fl_set_object_lcol(col[1], FL_INACTIVE);
- fl_deactivate_object(col[1]);
- }
- else
- {
- fl_set_object_lcol(col[1], FL_BLACK);
- fl_activate_object(col[1]);
- }
-
- if (lframe - tptr->frame || lbk - tptr->bk || leffects - tptr->se)
- {
- render_text(tptr);
- lframe = tptr->frame;
- lbk = tptr->bk;
- leffects = tptr->se;
- }
- }
-
- /*****************************************************************
- * finish up
- *****************************************************************/
- /* ARGSUSED */
- static void
- text_finish(FL_OBJECT * obj, long q)
- {
- fl_qenter(KEYBD, 27);
- /* left do_text do the cleanup */
- }
-
- /*****************************************************************
- * Delete all text. Real work is done by del_text. This is just
- * to get the prototype right
- *******************************************************************/
-
- /* ARGSUSED */
- static void
- del_dummy(FL_OBJECT * q, long p)
- {
-
- del_text(); /* this routine sets totaltext to zero */
- imgptr->io->display(imgptr, 0, 1);
- render_text(tptr);
-
- }
-
- /*********************************************************
- * Request a saving: if q == 1, newline
- *********************************************************/
- /* ARGSUSED */
- static void
- save_cb(FL_OBJECT * obj, long q)
- {
- save_text(q);
- }
-
- /*******************************************************************
- * Main form
- ******************************************************************/
- static void
- create_form_text(void)
- {
- FL_OBJECT *obj;
- const char *sep = "-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=";
- static int ok;
- float x, y, dx, dy;
- int i;
-
- if (ok)
- return;
- textform = fl_bgn_form(FL_NO_BOX, 295.0, 310.0);
- obj = fl_add_box(FL_UP_BOX, 0.0, 0.0, 295.0, 310.0, "");
- fl_set_object_color(obj, 9, 47);
- obj = fl_add_button(FL_HIDDEN_BUTTON, 0.0, 0.0, 295.0, 310.0, "");
- fl_set_call_back(obj, help_cb, HELP_TEXT);
-
- /* font */
- fchoice = obj = fl_add_choice(FL_NCH, 60.0, 270.0, 210.0, 25.0, "Font");
- fl_set_object_boxtype(obj, FL_RSHADOW_BOX);
- fl_set_call_back(obj, select_font, 0);
- fl_set_choice_fontsize(obj, 11.0);
-
- /* input */
- input = obj = fl_add_input(FL_NORMAL_INPUT, 10.0, 40.0, 275.0, 20.0, "");
- fl_set_object_boxtype(obj, FL_BORDER_BOX);
- fl_set_object_color(obj, 13, 50);
- fl_set_object_lsize(obj, 8.0);
- fl_set_call_back(obj, get_newtext, 0);
-
- obj = fl_add_text(FL_NT, 5.0, 145.0, 280.0, 10.0, sep);
- fl_set_object_lsize(obj, FL_SMALL_FONT);
- fl_set_object_lstyle(obj, FL_BOLD_STYLE);
-
- /* size group */
- fl_bgn_group();
- dx = 30.0;
- dy = 30.0;
- for (x = 15, y = 190, i = 0; i < 6; i += 2, y -= 20)
- {
- size[i] = obj = fl_add_roundbutton(FL_RB, x, y, dx, dy, "");
- fl_set_object_lsize(obj, FL_SMALL_FONT);
- fl_set_object_lstyle(obj, FL_BOLD_STYLE);
- fl_set_call_back(obj, fontsize_cb, i);
- size[i + 1] = obj = fl_add_roundbutton(FL_RB, x + 65, y, dx, dy, "");
- fl_set_object_lsize(obj, FL_SMALL_FONT);
- fl_set_object_lstyle(obj, FL_BOLD_STYLE);
- fl_set_call_back(obj, fontsize_cb, i + 1);
- }
- fl_end_group();
- scounter = obj = fl_add_counter(FL_NC, 15.0, 220.0, 115.0, 25.0, "Size");
- fl_set_object_color(obj, 12, 4);
- fl_set_object_lsize(obj, FL_SMALL_FONT);
- fl_set_object_align(obj, FL_ALIGN_TOP);
- fl_set_object_lstyle(obj, FL_BOLD_STYLE);
- fl_set_call_back(obj, fontsize_cb, 0);
-
- /* direction group */
- x = 160.0;
- y = 190.0;
- dy = 30;
- fl_bgn_group();
- for (i = 0; i < 4; i += 2, y -= dy)
- {
- ra[i] = obj = fl_add_roundbutton(FL_RB, x, y, 30.0, dy, "");
- fl_set_object_lsize(obj, FL_SMALL_FONT);
- fl_set_object_lstyle(obj, FL_BOLD_STYLE);
- fl_set_call_back(obj, select_orientation, i);
- ra[i + 1] = obj = fl_add_roundbutton(FL_RB, 225.0, y, 30.0, dy, "");
- fl_set_object_lsize(obj, FL_SMALL_FONT);
- fl_set_object_lstyle(obj, FL_BOLD_STYLE);
- fl_set_call_back(obj, select_orientation, i + 1);
- }
-
- rcounter = obj = fl_add_counter(FL_NC, 155, 220, 120, 25, "Rotation");
- fl_set_object_color(obj, 12, 4);
- fl_set_object_lsize(obj, FL_SMALL_FONT);
- fl_set_object_align(obj, FL_ALIGN_TOP);
- fl_set_object_lstyle(obj, FL_BOLD_STYLE);
- fl_set_call_back(obj, select_orientation, 0);
- fl_end_group();
-
-
- /* misc group */
- fl_bgn_group();
- col[0] = obj = fl_add_roundbutton(FL_NB, 15, 90, 30, 30, "TextColor");
- fl_set_object_color(obj, 7, 4);
- fl_set_object_lsize(obj, 10.0);
- fl_set_call_back(obj, select_color_cb, TC);
-
- col[1] = obj = fl_add_roundbutton(FL_NB, 100.0, 90.0, 30, 30, "FrameCol");
- fl_set_object_color(obj, 7, 4);
- fl_set_object_lsize(obj, 10.0);
- fl_set_object_lcol(obj, FL_INACTIVE);
- fl_deactivate_object(obj);
- fl_set_call_back(obj, select_color_cb, FC);
-
- col[2] = obj = fl_add_roundbutton(FL_NB, 190, 90, 30, 30, "BackgrdCol");
- fl_set_object_color(obj, 7, 4);
- fl_set_object_lsize(obj, 10.0);
- fl_set_call_back(obj, select_color_cb, BC);
- fl_set_object_lcol(obj, FL_INACTIVE);
- fl_deactivate_object(obj);
-
- frame = obj = fl_add_roundbutton(FL_PB, 100, 115, 30, 30.0, "Frame");
- fl_set_object_color(obj, 7, 1);
- fl_set_object_lsize(obj, 10.0);
- fl_set_call_back(obj, frame_bk_cb, 0);
- bk = obj = fl_add_roundbutton(FL_PB, 190.0, 115.0, 35, 30, "Background");
- fl_set_object_color(obj, 7, 1);
- fl_set_object_lsize(obj, 10.0);
- fl_set_call_back(obj, frame_bk_cb, 0);
-
- /* Special effects */
- effects = obj = fl_add_choice(FL_NCH, 20, 120.0, 80, 25, "");
- fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
- fl_set_choice_fontsize(obj, 10.0);
- i = 0;
- while (seffect_name[i])
- {
- fl_addto_choice(obj, seffect_name[i]);
- i++;
- }
- fl_set_choice(obj, 1);
- fl_set_call_back(obj, se_call_back, 0);
-
- x = 20.0;
- y = 65.0;
- dx = 80;
- dy = 25;
- obj = fl_add_choice(FL_NC, x, y, dx, dy, "");
- fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
- fl_set_choice_fontsize(obj, 10.0);
- fl_addto_choice(obj, "Left");
- fl_addto_choice(obj, "Center");
- fl_addto_choice(obj, "Right");
- fl_set_choice(obj, placement + 1);
- fl_set_call_back(obj, justification_cb, 0);
-
- x += dx + 5;
- obj = fl_add_choice(FL_NC, x, y, dx, dy, "");
- fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
- fl_set_choice_fontsize(obj, 10.0);
- fl_addto_choice(obj, "ScreenFont");
- fl_addto_choice(obj, "PrinterFont");
- fl_set_call_back(obj, preview_cb, 0);
-
- x += dx + 5;
- obj = fl_add_choice(FL_NC, x, y, dx, dy, "");
- fl_set_object_boxtype(obj, FL_ROUNDED_BOX);
- fl_set_choice_fontsize(obj, 10.0);
- fl_addto_choice(obj, "Deferred");
- fl_addto_choice(obj, "Immediate");
- fl_set_choice(obj, immediate + 1);
- fl_set_call_back(obj, immediate_cb, 0);
-
- fl_end_group();
-
- dx = 65.0;
- dy = 25.0;
- x = 20;
- fl_bgn_group();
-
- obj = fl_add_button(FL_NB, x, 10.0, dx, dy, "DelAll");
- fl_set_call_back(obj, del_dummy, 0);
- fl_set_object_lsize(obj, 10.0);
- fl_set_object_color(obj, FL_MAGIC1, FL_RED);
-
- obj = fl_add_button(FL_NB, x + dx, 10.0, dx, dy, "Done");
- fl_set_object_lsize(obj, 10.0);
- fl_set_object_color(obj, FL_MAGIC1, FL_GREEN);
- fl_set_call_back(obj, text_finish, 0);
-
- obj = fl_add_button(FL_NB, x + 2.0 * dx, 10.0, dx, dy, "NewLine");
- fl_set_object_lsize(obj, 10.0);
- fl_set_call_back(obj, save_cb, 1);
-
- obj = fl_add_button(FL_NB, x + 3.0 * dx, 10.0, dx, dy, "OK");
- fl_set_object_color(obj, FL_MAGIC1, FL_YELLOW);
- fl_set_object_lsize(obj, 10.0);
- fl_set_call_back(obj, save_cb, 0);
-
- fl_end_group();
- fl_end_form();
- ok = 1;
- }
-